module controller.menu;

import std.json : JSONValue;
import std.datetime.systime : Clock;
import std.algorithm : filter;
import std.array : array;
import std.conv : to;

import vibe.http.server : HTTPServerRequest, HTTPServerResponse;
import vibe.data.json : Json, deserializeJson;

import models.menu;
import repository.user;
import repository.menu;
import dtos.menu;
import dtos.route;
import utils.respdata;
import utils.objmapping : mappingToObject;
import utils.jwt;

import std.stdio : writeln;

/** 
 * 获取路由列表
 */
void getRoutes(HTTPServerRequest req, HTTPServerResponse resp)
{
    if ("Authorization" !in req.headers)
    {
        resp.writeJsonBody(RespData.newData(401, "请登录"), 401);
        return;
    }
    string token = req.headers["Authorization"];
    // writeln(token);
    if (!validateToken(token))
    {
        resp.writeJsonBody(RespData.newData(401, "token验证失败"), 401);
        return;
    }

    auto tokenData = decodeToken(token);
    auto exp = tokenData.claims.exp;
    // writeln("token exp:");
    // writeln(exp);
    long now = Clock.currTime.toUnixTime();
    if (exp < now)
    {
        resp.writeJsonBody(RespData.newData(401, "token已过期"), 401);
        return;
    }

    auto jwtUser = tokenData.claims.getObject("user");
    if (!jwtUser)
    {
        resp.writeJsonBody(RespData.newData(401, "token不正确"), 401);
        return;
    }

    // writeln(jwtUser["userId"]);

    long userId = jwtUser["userId"].get!long;
    auto user = getUserById(userId);

    if (user.roles.length <= 0 && user.roles[0] is null && user.roles[0].menus.length <= 0)
    {
        JSONValue data;
        data.array = [];
        resp.writeJsonBody(RespData.newData(200, "ok", data));
        return;
    }

    // 用户拥有的角色名集合
    import std.algorithm : each;

    string[] roles;
    user.roles.each!(x => roles ~= x.code);

    // 用户拥有路由信息
    auto menus = filter!(x => x.type != "BUTTON")(user.roles[0].menus);

    TopRouteDto[] topRoutes;
    SubRouteDto[] subRoutes;
    foreach (menu; menus)
    {
        if (menu.parentId == 0)
        {
            auto topRoute = new TopRouteDto();
            topRoute.path = menu.routePath;
            topRoute.component = menu.component;
            if (topRoute.path == "/system")
            {
                topRoute.redirect = "/system/user";
            }
            topRoute.meta = new Meta(menu.name, menu.icon, roles);
            topRoutes ~= topRoute;
        }
        else
        {
            auto subRoute = new SubRouteDto();
            subRoute.path = menu.routePath;
            subRoute.component = menu.component;
            subRoute.name = menu.routeName;
            subRoute.meta = new Meta(menu.name, menu.icon, roles);
            subRoutes ~= subRoute;
        }
    }
    foreach (ref topRoute; topRoutes)
    {
        foreach (SubRouteDto subRoute; subRoutes)
        {
            topRoute.children ~= subRoute;
        }
    }

    resp.writeJsonBody(RespData.newData!(TopRouteDto[])(200, "ok", topRoutes));
}

/** 
 * 获取菜单列表
 */
void getMenuList(HTTPServerRequest req, HTTPServerResponse resp)
{
    auto menus = getAllMenus();

    MultilevelMenuDto[] oneLevelMenus = [];
    MultilevelMenuDto[] otherMenus = [];
    foreach (menu; menus)
    {
        if (menu.parentId == 0)
        {
            oneLevelMenus ~= mappingToObject!(MultilevelMenuDto, Menu)(menu);
        }
        else
        {
            otherMenus ~= mappingToObject!(MultilevelMenuDto, Menu)(menu);
        }
    }

    // MultilevelMenuDto[] twoLevelMenus = [];
    // foreach (ref oneLevelMenu; oneLevelMenus)
    // {
    //     foreach (otherMenu; otherMenus)
    //     {
    //         if (otherMenu.parentId == oneLevelMenu.id)
    //         {
    //             // 二级菜单
    //             twoLevelMenus ~= otherMenu;

    //             getTreeMenus(twoLevelMenus, otherMenus);

    //             oneLevelMenu.children = twoLevelMenus;
    //         }
    //     }
    // }

    foreach (ref oneLevelMenu; oneLevelMenus)
    {
        oneLevelMenu.children = array(filter!(x => x.parentId == oneLevelMenu.id)(otherMenus));
        foreach (ref twoLevelMenu; oneLevelMenu.children)
        {
            twoLevelMenu.children = array(filter!(y => y.parentId == twoLevelMenu.id)(otherMenus));
        }
    }

    resp.writeJsonBody(RespData.newData!(MultilevelMenuDto[])(200, "ok", oneLevelMenus));
}

/** 
 * 三级菜单
 * Params:
 *   twoLevelMenus = 
 * Returns: 
 */
private void getTreeMenus(ref MultilevelMenuDto[] twoLevelMenus, MultilevelMenuDto[] otherMenus)
{
    foreach (ref twoLevelMenu; twoLevelMenus)
    {
        foreach (otherMenu; otherMenus)
        {
            if (otherMenu.parentId == twoLevelMenu.id)
            {
                twoLevelMenu.children ~= otherMenu;
            }
        }
    }
}

/** 
 * 获取菜单下拉列表
 */
void getMenuOptions(HTTPServerRequest req, HTTPServerResponse resp)
{
    auto menus = getAllMenus();

    MultilevelMenuDto[] oneLevelMenus = [];
    MultilevelMenuDto[] otherMenus = [];
    foreach (menu; menus)
    {
        if (menu.parentId == 0)
        {
            oneLevelMenus ~= mappingToObject!(MultilevelMenuDto, Menu)(menu);
        }
        else
        {
            otherMenus ~= mappingToObject!(MultilevelMenuDto, Menu)(menu);
        }
    }

    foreach (ref oneLevelMenu; oneLevelMenus)
    {
        oneLevelMenu.children = array(filter!(x => x.parentId == oneLevelMenu.id)(otherMenus));
        foreach (ref twoLevelMenu; oneLevelMenu.children)
        {
            twoLevelMenu.children = array(filter!(y => y.parentId == twoLevelMenu.id)(otherMenus));
        }
    }

    MenuOption[] menuOptions = [];
    foreach (oneLevelMenu; oneLevelMenus)
    {
        auto temp = new MenuOption(oneLevelMenu.id, oneLevelMenu.name);
        if (oneLevelMenu.children && oneLevelMenu.children.length > 0) // 有第二层
        {
            foreach (twoLevelMenu; oneLevelMenu.children)
            {
                auto temp2 = new MenuOption(twoLevelMenu.id, twoLevelMenu.name);
                if (twoLevelMenu.children && twoLevelMenu.children.length > 0) // 有第三层
                {
                    foreach (threeLevelMenu; twoLevelMenu.children)
                    {
                        temp2.children ~= new MenuOption(threeLevelMenu.id, threeLevelMenu.name);
                    }
                }

                temp.children ~= temp2;
            }
        }

        menuOptions ~= temp;
    }

    resp.writeJsonBody(RespData.newData!(MenuOption[])(200, "ok", menuOptions));
}

/** 
 * 添加菜单
 */
void addMenu(HTTPServerRequest req, HTTPServerResponse resp)
{
    // 接收前端数据
    Json json = req.json;
    if (json.length == 0)
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }

    MenuDtoForCreate newMenu = deserializeJson!(MenuDtoForCreate)(json);

    if (newMenu.name == "" || newMenu.type == "")
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }
    auto tempData = mappingToObject!(Menu, MenuDtoForCreate)(newMenu);
    tempData.routePath = newMenu.path;
    tempData.createTime = Clock.currTime.toUnixTime();

    bool res = doAddMenu(tempData);
    if (!res)
    {
        resp.writeJsonBody(RespData.newData(500, "操作失败"), 500);
        return;
    }

    resp.writeJsonBody(RespData.newData(200, "ok"), 200);
}

/**
* 编辑时获取菜单详情信息
*/
void getMenuInfo(HTTPServerRequest req, HTTPServerResponse resp)
{
    if ("menuid" !in req.params)
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }

    auto menu = getMenuById(to!long(req.params["menuid"]));
    MenuDto2 menuDto = mappingToObject!(MenuDto2, Menu)(menu);
    menuDto.path = menu.routePath;

    resp.writeJsonBody(RespData.newData!(MenuDto2)(200, "ok", menuDto));
}

/** 
 * 编辑菜单
 */
void editMenu(HTTPServerRequest req, HTTPServerResponse resp)
{
    if ("menuid" !in req.params)
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }
    long reqMenuid = to!long(req.params["menuid"]);

    // 接收前端json数据
    Json json = req.json;
    if (json.length == 0)
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }
    auto upMenu = deserializeJson!(MenuDtoForUpdate)(json);
    if (upMenu.name == "" || upMenu.type == "")
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }

    // 提交修改数据
    auto tempData = mappingToObject!(Menu, MenuDtoForUpdate)(upMenu);
    tempData.routePath = upMenu.path;
    tempData.updateTime = Clock.currTime.toUnixTime();
    auto res = doUpdateMenu(reqMenuid, tempData);
    if (!res)
    {
        resp.writeJsonBody(RespData.newData(500, "操作失败"), 500);
        return;
    }

    resp.writeJsonBody(RespData.newData(200, "ok"), 200);
}

/**
* 删除菜单
*/
void deleteMenu(HTTPServerRequest req, HTTPServerResponse resp)
{
    if ("menuid" !in req.params)
    {
        resp.writeJsonBody(RespData.newData(400, "错误的请求"), 400);
        return;
    }

    bool res = deleteMenuById(to!long(req.params["menuid"]));
    if (!res)
    {
        resp.writeJsonBody(RespData.newData(500, "操作失败"), 500);
        return;
    }

    resp.writeJsonBody(RespData.newData(200, "ok"));
}
